package service

import (
	"errors"
	"fmt"
	"multimedia/smscode"
	"multimedia/utils"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	log "github.com/sirupsen/logrus"
)

// 生成滑块验证码
func (s *Srv) VerificationCodeForSlider(c *gin.Context) {
	phoneNo := c.Query("phoneNo")
	key := fmt.Sprint(utils.SLIDER_VERIFICATION_CODE_KEY, phoneNo)
	res := make(map[string]string)
	redVal, err := s.redis.GetKeyString(key)
	if err != nil {
		log.WithField("Func", "VerificationCodeForSlider").Warnf("get slider vscode redis fail", err)
	}
	if redVal != "" {
		res["sliderCode"] = redVal
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})
		return
	}
	vscode := utils.Get6bitRandomDigit()
	err = s.redis.UpdateKey(key, vscode, utils.VERIFICATION_CODE_EXPIRE_TIME)
	if err != nil {
		log.WithField("Func", "VerificationCodeForSlider").Errorf("put slider vscode redis error", err)
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	res["sliderCode"] = vscode
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})
}

// // 生成验证码
// func (s *Srv) VerificationCodeGenerate(c *gin.Context) {
// 	phoneNo := c.Query("phoneNo")
// 	svsc := c.Query("sliderCode")
// 	key := fmt.Sprint(utils.SLIDER_VERIFICATION_CODE_KEY, phoneNo)
// 	vscode, err := s.redis.GetKeyString(key)
// 	if err != nil || svsc != vscode {
// 		log.WithField("Func", "VerificationCodeGenerate").Warnf("get slider vscode redis fail", err)
// 		c.JSON(http.StatusOK, gin.H{"code": utils.VerifyCodeErr, "msg": "滑块验证失败！"})
// 		return
// 	}
// 	vcodeRedisKey := utils.VERIFICATION_CODE_KEY + phoneNo
// 	retval, err := s.redis.GetKeyString(vcodeRedisKey)
// 	if err != nil {
// 		log.WithField("Func", "VerificationCodeGenerate").Warnf("get vcode redis fail", err)
// 	}
// 	if retval != "" {
// 		c.JSON(http.StatusOK, gin.H{"code": utils.VerifyCodeErr, "msg": "60s内不允许重复获取验证码！"})
// 		return
// 	}
// 	vcode := utils.Get6bitRandomDigit()
// 	err = s.redis.UpdateKey(vcodeRedisKey, vcode, utils.VERIFICATION_CODE_EXPIRE_TIME)
// 	if err != nil {
// 		log.WithField("Func", "VerificationCodeGenerate").Errorf("put vcode redis error", err)
// 		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
// 		return
// 	}
// 	res := map[string]string{
// 		"vcode": vcode,
// 	}
// 	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})
// }

// 生成4位验证码
func (s *Srv) GetVSCode(c *gin.Context) {
	phoneNo := c.Query("phoneNo")
	vcode := utils.Get4bitRandomDigit()
	vcodeRedisKey := utils.VERIFICATION_CODE_KEY + phoneNo
	err := s.redis.UpdateKey(vcodeRedisKey, vcode, utils.VERIFICATION_CODE_EXPIRE_TIME)
	if err != nil {
		log.WithField("Func", "GetVSCode").Errorf("put vcode redis error", err)
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	res := map[string]string{
		"vcode": vcode,
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})
}

// new生成图片验证码
func (s *Srv) NewGetVSCode(c *gin.Context) {
	phoneNo := c.Query("phoneNo")
	if phoneNo == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	id, base64, err := utils.CaptMake()
	if err != nil {
		log.WithField("Func", "GetNewVSCode").Errorf("Generate vcode  error", err)
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	vcodeRedisKey := utils.CAPTCHA_KEY + phoneNo
	rerr := s.redis.UpdateKey(vcodeRedisKey, id, utils.VERIFICATION_CODE_REQ_TIME)
	if rerr != nil {
		log.WithField("Func", "GetVSCode").Errorf("put CAPTCHA key redis error", err)
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	res := map[string]string{
		"base64": base64,
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})

}

// 注册
func (s *Srv) Register(c *gin.Context) {
	phoneNo := c.Query("phoneNo")
	password := c.Query("password")
	vcode := c.Query("vcode")
	if len(phoneNo) < 11 {
		c.JSON(http.StatusOK, gin.H{"code": utils.PhoneNoErr, "msg": "手机号码格式错误，请确认"})
		return
	}
	if password == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.PasswordError, "msg": "密码不能为空"})
		return
	}
	record, err := s.CheckVSCode(phoneNo, vcode)
	if record != utils.Success {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqVSCodeErr, "msg": err.Error()})
		return
	}
	userRes := s.mysql.GetUserInfoByPhone(phoneNo)
	if userRes == nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "系统错误"})
		return
	}
	//账户已存在
	if userRes.Id != 0 {
		c.JSON(http.StatusOK, gin.H{"code": utils.MobileRegistered, "msg": "注册失败"})
		return
	}
	password = utils.Sha1(password, nil)
	var userAdd utils.AppUser
	userAdd.PhoneNo = phoneNo
	userAdd.Nickname = phoneNo
	userAdd.Password = password
	userId := s.mysql.InsertUserInfo(&userAdd)
	if userId == 0 {
		c.JSON(http.StatusOK, gin.H{"code": utils.UserNoRegister, "msg": "注册失败"})
		return
	}
	// 初始化个人设置项
	s.mysql.AddSettings(userId)
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(true)})
}

func (s *Srv) ModifyPassword(c *gin.Context) {
	var req utils.ModifyPwdReq
	if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
		log.WithField("func", "ModifyPassword").Errorf(err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": err.Error()})
		return
	}

	if len(req.PhoneNo) < 11 {
		msg := fmt.Sprintf("请使用11位手机号，目前手机号位为%d", len(req.PhoneNo))
		c.JSON(http.StatusOK, gin.H{"code": utils.PhoneNoErr, "msg": msg})
		return
	}
	if req.PassWord == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.PasswordError, "msg": "密码不能为空"})
		return
	}
	retcode, err := s.CheckVSCode(req.PhoneNo, req.VCode)
	if retcode != utils.Success {
		c.JSON(http.StatusOK, gin.H{"code": retcode, "msg": err.Error()})
	} else {
		s.mysql.UpdateUserPasswd(utils.Sha1(req.PassWord, nil), req.PhoneNo)
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(true)})
	}
}
func (s *Srv) CheckVSCode(phoneNo string, vcode string) (int, error) {
	if len(vcode) < 6 {
		return utils.ReqVSCodeErr, errors.New("验证码错误")
	}
	vcodeRedisKey := utils.VERIFICATION_CODE_KEY + phoneNo
	retval, err := s.redis.GetKeyString(vcodeRedisKey)
	if err != nil {
		log.WithField("Func", "CheckVSCode").Warnf("key not exist %s,%v", vcodeRedisKey, err)
	}
	if vcode != retval {
		return utils.ReqVSCodeErr, errors.New("验证码错误")
	}
	s.redis.DelKey(vcodeRedisKey)
	return utils.Success, nil
}
func (s *Srv) TelVsCodeReq(c *gin.Context) {
	var req utils.TelVscodeReq
	if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
		log.WithField("func", "TelVsCodeReq").Errorf(err.Error())
		//c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": err.Error()})
		c.JSON(http.StatusBadRequest, gin.H{"result": utils.EncryptDataByAes(gin.H{"code": utils.ReqParamErr, "msg": err.Error()})})
		return
	}
	phone := req.PhoneNo
	if len(phone) != 11 {
		//c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": "手机号错误"})
		c.JSON(http.StatusBadRequest, gin.H{"result": utils.EncryptDataByAes(gin.H{"code": utils.ReqParamErr, "msg": "手机号错误"})})
		return
	}
	reqRedisKey := utils.VERIFICATION_CODE_REQ_KEY + phone
	retval, err := s.redis.GetKeyString(reqRedisKey)
	if err == nil && retval != "" {
		//c.JSON(http.StatusOK, gin.H{"code": utils.ReqVSCoderepeat, "msg": "获取验证码较频繁，请稍后再试"})
		c.JSON(http.StatusOK, gin.H{"result": utils.EncryptDataByAes(gin.H{"code": utils.ReqVSCoderepeat, "msg": "获取验证码较频繁，请稍后再试"})})
		return
	}
	reqType := req.Type
	if reqType == utils.MsgType_ForgetPwd || reqType == utils.MsgType_ModifyPwd {
		userinfo := s.mysql.GetUserInfoByPhone(phone)
		if userinfo == nil {
			//c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "系统错误"})
			c.JSON(http.StatusOK, gin.H{"result": utils.EncryptDataByAes(gin.H{"code": utils.DBError, "msg": "系统错误"})})
			return
		}
		//手机号不存在
		if userinfo.Id == 0 {
			//c.JSON(http.StatusOK, gin.H{"code": utils.DateNotFound, "msg": "系统内部错误"})
			c.JSON(http.StatusOK, gin.H{"result": utils.EncryptDataByAes(gin.H{"code": utils.DateNotFound, "msg": "系统内部错误"})})
			return
		}
	}
	reqcode, msg := smscode.SendSms("", phone, "34081")
	if reqcode == "" {
		log.WithField("func", "TelVsCodeReq").Errorf("request sms succesful :%s", msg)
		//c.JSON(http.StatusOK, gin.H{"code": utils.ReqVSCodeErr, "msg": "获取验证码失败"})
		c.JSON(http.StatusOK, gin.H{"result": utils.EncryptDataByAes(gin.H{"code": utils.ReqVSCodeErr, "msg": "获取验证码失败"})})
	} else {
		vcodeRedisKey := utils.VERIFICATION_CODE_KEY + phone
		s.redis.UpdateKey(vcodeRedisKey, reqcode, utils.VERIFICATION_CODE_EXPIRE_TIME)
		reqRedisKey := utils.VERIFICATION_CODE_REQ_KEY + phone
		s.redis.UpdateKey(reqRedisKey, reqcode, utils.VERIFICATION_CODE_REQ_TIME)
		//c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(true)})
		c.JSON(http.StatusOK, gin.H{"result": utils.EncryptDataByAes(gin.H{"code": utils.Success, "msg": "", "data": true})})
	}
}

func (s *Srv) NewLogin(c *gin.Context) {
	var loginreq utils.NewLoginReq
	if err := c.ShouldBindBodyWith(&loginreq, binding.JSON); err != nil {
		log.WithField("func", "NewLogin").Errorf(err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": err.Error()})
		return
	}
	log.WithField("func", "NewLogin").Infof("the phone:%s,%d,,%v", loginreq.PhoneNo, len(loginreq.PhoneNo), loginreq)

	if len(loginreq.PhoneNo) < 11 {
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.PhoneNoErr, "msg": "手机号错误"})
		return
	}
	if loginreq.Type == utils.LOGIN_TEL_CODE {
		if loginreq.TelVerifyCode == "" {
			c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": "验证码不能为空"})
			return
		}
		retcode, userRes, err := s.LoginByTelCode(loginreq.PhoneNo, loginreq.TelVerifyCode, false)
		if retcode != utils.Success {
			c.JSON(http.StatusOK, gin.H{"code": retcode, "msg": err.Error()})
		} else {
			c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(userRes)})
		}
	} else if loginreq.Type == utils.LOGIN_TEL_PWD {
		retcode, userRes, err := s.LoginByPassWd(loginreq.PhoneNo, loginreq.PassWord, loginreq.CaptchaValue)
		if retcode != utils.Success {
			c.JSON(http.StatusOK, gin.H{"code": retcode, "msg": err.Error()})
		} else {
			c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(userRes)})
		}
	}
}

// 登录
func (s *Srv) LoginByPassWd(phoneNo string, password string, captchaValue string) (int, *utils.UserRes, error) {

	userRes := s.mysql.GetUserInfoByPhone(phoneNo)
	if userRes == nil {
		return utils.DBError, nil, errors.New("系统错误")
	}
	//账号不存在，请先注册
	if userRes.Id == 0 {
		return utils.UserNoRegister, nil, errors.New("账户或密码错误")
	}
	if userRes.Password == "" {
		return utils.PasswordError, nil, errors.New("账户或密码错误")
	}
	password = utils.Sha1(password, nil)
	if password != userRes.Password {
		return utils.PasswordError, nil, errors.New("账户或密码错误")
	}
	vcodeRedisKey := utils.CAPTCHA_KEY + phoneNo
	captchaId, _ := s.redis.GetKeyString(vcodeRedisKey)
	if captchaId != "" {
		// 删除图形验证码缓存
		s.redis.DelKey(vcodeRedisKey)
		if captchaValue != "" {
			if utils.CaptVerify(captchaId, captchaValue) != true {
				return utils.DBError, nil, errors.New("验证码错误")
			}
		} else {
			return utils.CaptchaNull, nil, errors.New("验证码不能为空")
		}
	}
	if captchaValue != "" && captchaId == "" {
		return utils.DBError, nil, errors.New("验证码过期")
	}
	// 处理登录token
	UId := strconv.FormatInt(userRes.Id, 10)
	token := s.updateToken(UId)
	if token == "" {
		return utils.ServiceInternalErr, nil, errors.New("系统错误")
	}
	userRes.Token = token
	return utils.Success, userRes, nil
}

func (s *Srv) LoginByTelCode(phone string, vcode string, debug bool) (int, *utils.UserRes, error) {
	// vcodeRedisKey := utils.VERIFICATION_CODE_KEY + phone
	// retval, err := s.redis.GetKeyString(vcodeRedisKey)
	// if err != nil {
	// 	log.WithField("Func", "Login").Warnf("get vcode redis error", err)
	// }
	// if retval == "" {
	// 	log.WithField("Func", "Login").Errorf("the verifyCode is not exist the phone is:%d", phone)
	// 	return utils.VerifyCodeErr, nil, errors.New("验证码无效，请重新获取！")
	// }
	if debug {
		if vcode != "135246" {
			log.WithField("Func", "LoginByTel").Errorf("the vcode is error %s,%s", vcode, phone)
			return utils.VerifyCodeErr, nil, errors.New("验证码错误！")
		}
	} else {
		record, err := s.CheckVSCode(phone, vcode)
		if record != utils.Success {
			return record, nil, err
		}
	}
	userRes := s.mysql.GetUserInfoByPhone(phone)
	if userRes == nil {
		return utils.DBError, nil, errors.New("数据库服务器发生错误")
	}
	// 注册
	if userRes.Id == 0 {
		var userAdd utils.AppUser
		userAdd.PhoneNo = phone
		userAdd.Nickname = phone
		userId := s.mysql.InsertUserInfo(&userAdd)
		if userId == 0 {
			return utils.UserNoRegister, nil, errors.New("注册失败")
		}
		// 初始化个人设置项
		s.mysql.AddSettings(userId)
		userRes.Id = userId
		userRes.Nickname = phone
		userRes.PhoneNo = phone
	}
	// 处理登录token
	UId := strconv.FormatInt(userRes.Id, 10)
	token := s.updateToken(UId)
	if token == "" {
		return utils.ServiceInternalErr, nil, errors.New("token失效,请重试")
	}
	userRes.Token = token
	// 删除验证码缓存
	return utils.Success, userRes, nil
}

// 登录/注册
func (s *Srv) Login(c *gin.Context) {
	phoneNo := c.Query("phoneNo")
	vcodeStr := c.Query("vcode")
	retcode, userRes, err := s.LoginByTelCode(phoneNo, vcodeStr, true)
	if retcode != utils.Success {
		c.JSON(http.StatusBadRequest, gin.H{"code": retcode, "msg": err.Error()})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(userRes)})
	}
}

// 退出登录（删除token）
func (s *Srv) Logout(c *gin.Context) {
	userId := c.Query("userId")
	tokenRedisKey := utils.USER_LOGIN_TOKEN + userId
	e := s.redis.DelKey(tokenRedisKey)
	if e != nil {
		log.WithField("Func", "Login").Errorf(e.Error())
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(true)})
}

// 更新token
func (s *Srv) UpdateToken(c *gin.Context) {
	userId := c.Query("userId")
	token := s.updateToken(userId)
	if token == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	m := map[string]string{
		"token": token,
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(m)})
}

// 添加或者更新token
func (s *Srv) updateToken(userId string) string {
	tokenRedisKey := utils.USER_LOGIN_TOKEN + userId
	token := utils.GenerateUserToken(userId, time.Now().Unix())
	e := s.redis.UpdateKey(tokenRedisKey, token, utils.USER_LOGIN_TOKEN_EXPIRE_TIME)
	if e != nil {
		log.WithField("Func", "updateToken").Errorf("update token error %v", e.Error())
		return ""
	}
	return token
}

// 校验token
func (s *Srv) CheckToken(c *gin.Context) {
	token := c.Request.Header.Get("Authorization")
	userId := c.Request.Header.Get("userId")
	if userId == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "请求头里放参数"})
		c.Abort()
		return
	}
	tokenRedisKey := utils.USER_LOGIN_TOKEN + userId
	reidsToken, e := s.redis.GetKeyString(tokenRedisKey)
	if e != nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		c.Abort()
		return
	}
	if token != reidsToken {
		c.JSON(http.StatusOK, gin.H{"code": utils.UserNoLogin, "msg": ""})
		c.Abort()
		return
	}
	c.Next()
}
